package controllers

import (
	"goravel/app/models"
	"goravel/app/scopes"
	"goravel/utils/response"

	"github.com/goravel/framework/contracts/http"
	"github.com/goravel/framework/facades"
)

type UserController struct {
	BaseController
}

func NewUserController() *UserController {
	return &UserController{}
}

// Index GET /users
func (c *UserController) Index(ctx http.Context) http.Response {
	var users []models.User
	var total int64

	page, perPage := c.GetPaginationParams(ctx)

	query := scopes.Query(ctx)

	// 打印生成的SQL
	// sqlInfo := query.ToSql()
	// fmt.Println(sqlInfo)

	if username := ctx.Request().Query("username"); username != "" {
		query = query.Where("username", "like", "%"+username+"%")
	}

	query = query.Select("id", "username", "created_at").OrderBy("id", "desc")

	if err := query.Paginate(page, perPage, &users, &total); err != nil {
		return response.Fail(ctx, http.StatusInternalServerError, facades.Lang(ctx).Get("errors.failed_to_fetch"))
	}

	return response.Paginate(ctx, users, total, page, perPage)
}

// Show GET /users/{id}
func (c *UserController) Show(ctx http.Context) http.Response {
	var model models.User

	if err := scopes.Query(ctx).FindOrFail(&model, ctx.Request().RouteInt("id")); err != nil {
		return response.Fail(ctx, http.StatusNotFound, facades.Lang(ctx).Get("errors.failed_to_fetch"))
	}

	return response.Success(ctx, http.Json{
		"data": model,
	})
}

// Store POST /users
func (c *UserController) Store(ctx http.Context) http.Response {
	validator, err := ctx.Request().Validate(map[string]string{
		"username": "required|string",
		"email":    "email",
		"password": "required|string",
	})

	if err != nil {
		return response.Fail(ctx, http.StatusBadRequest, "Validation failed: "+err.Error())
	}

	if validator.Fails() {
		return response.Fail(ctx, http.StatusBadRequest, validator.Errors().One())
	}

	var usernameExists bool
	if err := scopes.Query(ctx).Model(&models.User{}).Where("username", ctx.Request().Input("username")).Exists(&usernameExists); err != nil {
		return response.Fail(ctx, http.StatusBadRequest, facades.Lang(ctx).Get("errors.failed_to_fetch"))
	} else if usernameExists {
		return response.Fail(ctx, http.StatusBadRequest, facades.Lang(ctx).Get("errors.already_exists"))
	}

	password, _ := facades.Hash().Make(ctx.Request().Input("password"))
	user := models.User{
		Username: ctx.Request().Input("username"),
		Email:    ctx.Request().Input("email"),
		Password: password,
	}

	if err := scopes.Query(ctx).Create(&user); err != nil {
		facades.Log().Errorf("Failed to create user: %v, request data: %+v", err, ctx.Request().All())
		return response.Fail(ctx, http.StatusInternalServerError, facades.Lang(ctx).Get("errors.failed_to_create"))
	}

	userResponse := http.Json{
		"id":       user.ID,
		"username": user.Username,
		"email":    user.Email,
	}

	return response.Success(ctx, userResponse)
}

// Update PUT /users/{id}
func (c *UserController) Update(ctx http.Context) http.Response {
	var model models.User

	if err := scopes.Query(ctx).FindOrFail(&model, ctx.Request().RouteInt("id")); err != nil {
		return response.Fail(ctx, http.StatusNotFound, facades.Lang(ctx).Get("errors.failed_to_fetch"))
	}

	validator, err := ctx.Request().Validate(map[string]string{
		"email":    "string",
		"password": "string",
	})

	if err != nil {
		return response.Fail(ctx, http.StatusBadRequest, "Validation failed: "+err.Error())
	}

	if validator.Fails() {
		return response.Fail(ctx, http.StatusBadRequest, validator.Errors().One())
	}

	if email := ctx.Request().Input("email"); email != "" {
		model.Email = email
	}

	if password := ctx.Request().Input("password"); password != "" {
		hashedPassword, _ := facades.Hash().Make(password)
		model.Password = hashedPassword
	}

	if err := scopes.Query(ctx).Save(&model); err != nil {
		return response.Fail(ctx, http.StatusInternalServerError, facades.Lang(ctx).Get("errors.failed_to_update"))
	}

	return response.Success(ctx, http.Json{
		"data": model,
	})
}

// Destroy DELETE /users/{id}
func (c *UserController) Destroy(ctx http.Context) http.Response {
	var model models.User

	res, err := scopes.Query(ctx).Model(&model).Where("id", ctx.Request().RouteInt("id")).Delete()
	if err != nil {
		return response.Fail(ctx, http.StatusInternalServerError, facades.Lang(ctx).Get("errors.failed_to_delete"))
	}

	if res.RowsAffected == 0 {
		return response.Fail(ctx, http.StatusNotFound, facades.Lang(ctx).Get("errors.no_deleted"))
	}

	return response.Success(ctx, http.Json{
		"id":            model.ID,
		"rows_affected": res.RowsAffected,
	})
}

// Login POST /login
func (c *UserController) Login(ctx http.Context) http.Response {

	validator, err := ctx.Request().Validate(map[string]string{
		"username": "required|string",
		"password": "required|string",
	})

	if err != nil {
		return response.Fail(ctx, http.StatusBadRequest, "参数验证失败: "+err.Error())
	}

	if validator.Fails() {
		return response.Fail(ctx, http.StatusBadRequest, validator.Errors().One())
	}

	var user models.User

	if err := scopes.Query(ctx).Where("username", ctx.Request().Input("username")).First(&user); err != nil {
		return response.Fail(ctx, http.StatusUnauthorized, "用户名或密码错误")
	}

	if user.ID == 0 {
		return response.Fail(ctx, http.StatusUnauthorized, "用户名或密码错误")
	}

	if !facades.Hash().Check(ctx.Request().Input("password"), user.Password) {
		return response.Fail(ctx, http.StatusUnauthorized, "用户名或密码错误")
	}

	token, err := facades.Auth(ctx).Guard("admin").LoginUsingID(user.ID)
	if err != nil {
		return response.Fail(ctx, http.StatusInternalServerError, "生成 Token 失败: "+err.Error())
	}

	return response.Success(ctx, http.Json{
		"token": token,
		"user": http.Json{
			"id":       user.ID,
			"username": user.Username,
			"email":    user.Email,
		},
	})
}

// Logout POST /logout
func (c *UserController) Logout(ctx http.Context) http.Response {
	err := facades.Auth(ctx).Logout()
	if err != nil {
		return nil
	}
	return response.Success(ctx, http.Json{})
}

// GetCurrentUser GET /getCurrentUser
func (c *UserController) GetCurrentUser(ctx http.Context) http.Response {

	user, ok := ctx.Value("user").(models.User)
	if !ok {
		return response.Fail(ctx, http.StatusInternalServerError, "Failed to get user information")
	}

	// 获取用户角色
	roles, err := user.GetRoles()
	if err != nil {
		facades.Log().Errorf("Failed to get user roles: %v", err)
		roles = []models.Role{} // 设置为空数组，不影响返回
	}

	// 获取用户权限
	permissions, err := user.GetPermissions()
	if err != nil {
		facades.Log().Errorf("Failed to get user permissions: %v", err)
		permissions = []models.Permission{} // 设置为空数组，不影响返回
	}

	return response.Success(ctx, http.Json{
		"user": http.Json{
			"id":       user.ID,
			"username": user.Username,
			"email":    user.Email,
			"is_root":  user.IsRoot,
			"status":   user.Status,
		},
		"roles":       roles,
		"permissions": permissions,
	})
}

// GetUserPermissions GET /users/{id}/permissions
func (c *UserController) GetUserPermissions(ctx http.Context) http.Response {
	var user models.User

	if err := scopes.Query(ctx).FindOrFail(&user, ctx.Request().RouteInt("id")); err != nil {
		return response.Fail(ctx, http.StatusNotFound, facades.Lang(ctx).Get("errors.failed_to_fetch"))
	}

	permissions, err := user.GetPermissions()
	if err != nil {
		return response.Fail(ctx, http.StatusInternalServerError, "Failed to get user permissions")
	}

	return response.Success(ctx, http.Json{
		"permissions": permissions,
	})
}

// GetUserRoles GET /users/{id}/roles
func (c *UserController) GetUserRoles(ctx http.Context) http.Response {
	var user models.User

	if err := scopes.Query(ctx).FindOrFail(&user, ctx.Request().RouteInt("id")); err != nil {
		return response.Fail(ctx, http.StatusNotFound, facades.Lang(ctx).Get("errors.failed_to_fetch"))
	}

	roles, err := user.GetRoles()
	if err != nil {
		return response.Fail(ctx, http.StatusInternalServerError, "Failed to get user roles")
	}

	return response.Success(ctx, http.Json{
		"roles": roles,
	})
}
